﻿
namespace CodeBetter.Extensions
{
   using System;
   using System.Collections;
   using System.Collections.Generic;
   using System.ComponentModel;

   public static class IEnumerableExtensions
   {      
      /// <summary>
      /// Performs the specified action on each element of the list
      /// </summary>
      public static void Each<T>(this IEnumerable<T> list, Action<T> action)
      {
         if (action == null)
         {
            throw new ArgumentNullException("action");
         }
         var enumerator = list.GetEnumerator();
         while (enumerator.MoveNext())
         {
            action(enumerator.Current);
         }
      }
      /// <summary>
      /// Performs the specified action on each element of the list and includes
      /// an index value (starting at 0)
      /// </summary>
      public static void EachIndex<T>(this IEnumerable<T> list, Action<T, int> action)
      {
         if (action == null)
         {
            throw new ArgumentNullException("action");
         }
         var enumerator = list.GetEnumerator();
         var count = 0;
         while (enumerator.MoveNext())
         {
            action(enumerator.Current, count++);
         }
      }
      /// <summary>
      /// Validates that the predicate is true for each element of the list
      /// </summary>      
      public static bool TrueForAll<T>(this IEnumerable<T> list, Predicate<T> predicate)
      {
         if (predicate == null)
         {
            throw new ArgumentNullException("predicate");
         }
         var enumerator = list.GetEnumerator();
         while (enumerator.MoveNext())
         {
            if (!predicate(enumerator.Current))
            {
               return false;
            }
         }
         return true;
      }
      /// <summary>
      /// Retuns a list of all items matching the predicate
      /// </summary>      
      public static List<T> FindAll<T>(this IEnumerable<T> list, Predicate<T> predicate)
      {
         if (predicate == null)
         {
            throw new ArgumentNullException("predicate");
         }
         var found = new List<T>();
         var enumerator = list.GetEnumerator();
         while (enumerator.MoveNext())
         {
            if (predicate(enumerator.Current))
            {
               found.Add(enumerator.Current);
            }
         }
         return found;
      }
      /// <summary>
      /// Retuns the first matching item
      /// </summary>      
      public static T Find<T>(this IEnumerable<T> list, Predicate<T> predicate)
      {         
         if (predicate == null)
         {
            throw new ArgumentNullException("predicate");
         }         
         var enumerator = list.GetEnumerator();
         while (enumerator.MoveNext())
         {
            if (predicate(enumerator.Current))
            {
               return enumerator.Current;
            }
         }
         return default(T);
      }
      /// <summary>
      /// Finds the index of an item
      /// </summary>      
      public static int Index<T>(this IEnumerable<T> list, Predicate<T> predicate)
      {
         if (predicate == null)
         {
            throw new ArgumentNullException("predicate");
         }
         var enumerator = list.GetEnumerator();
         for (int i = 0; enumerator.MoveNext(); ++i)
         {
            if (predicate(enumerator.Current))
            {
               return i;
            }
         }
         return -1;
      }
      /// <summary>
      /// Determines whether or not the item exists
      /// </summary>      
      public static bool Exists<T>(this IEnumerable<T> list, Predicate<T> predicate)
      {
         return list.Index(predicate) > -1;
      }

      // todo distinction between IsNullOrEmpty, (IsNotNullOrEmpty) IsNull, (IsNotNull), and IsEmpty and (IsNotEmpty)
      // todo? IEnumString, IEnumConnections, IEnumConnectionPoints (lot more ComTypes)

      /// <summary>
      /// new
      /// </summary>
      /// <param name="list"></param>
      /// <returns></returns>
      public static bool IsNullOrEmpty(this IEnumerable list)
      {
         return list == null ? true : list.GetEnumerator().MoveNext() == false;
      }

      /// <summary>
      /// new
      /// </summary>
      /// <param name="list"></param>
      /// <returns></returns>
      /// <exception cref="ArgumentNullException"></exception>
      public static bool IsEmpty(this IEnumerable list)
      {
         if (list == null)
            throw new ArgumentNullException("list");
         return list.GetEnumerator().MoveNext() == false;
      }

      /// <summary>
      /// 
      /// </summary>
      /// <param name="list"></param>
      /// <returns></returns>
      public static bool IsNullOrEmpty(this IListSource list)
      {
         return list == null ? true : list.GetList().Count == 0;
      }

      // todo add IContainer

   }
}
   